package com.mongo.api;

import com.mongo.util.MongoIdWorker;
import com.tanhua.dubbo.mongo.MovementAPI;
import com.tanhua.mongo.Comment;
import com.tanhua.mongo.Friend;
import com.tanhua.mongo.Movement;
import com.tanhua.mongo.MovementTimeLine;
import com.tanhua.vo.MovementVo;
import com.tanhua.vo.PageResult;
import org.apache.dubbo.config.annotation.DubboService;
import org.bson.types.ObjectId;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.mapping.MongoId;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

@DubboService
public class MovementAPIImpl implements MovementAPI {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private MongoIdWorker mongoIdWorker;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public void publishMovements(MovementVo vo, Long userId) {
        //1 将movementVo转成movement
        Movement movement = new Movement();
        BeanUtils.copyProperties(vo,movement);
        movement.setLocationName(vo.getLocation());
        movement.setUserId(userId);
        movement.setCreated(System.currentTimeMillis());
        movement.setPid(mongoIdWorker.getNextId("movement"));
//        movement.setPid(stringRedisTemplate.opsForValue().increment("pid"));
        movement.setId(ObjectId.get());
        //2 保存movement
        mongoTemplate.save(movement);
        //调用异步方法
        saveMovementTimeLine(userId,movement);
    }


    //异步方法,底层采用多线程的方式
    @Async
    public void saveMovementTimeLine(Long userId,Movement movement){
        //3 查找好友关系
        Criteria criteria = Criteria.where("userId").is(userId);
        Query query = new Query(criteria);
        List<Friend> friendList = mongoTemplate.find(query, Friend.class);
        //4 保存好有时间线表
        friendList.forEach(friend ->{
            MovementTimeLine mtl = new MovementTimeLine();
            mtl.setMovementId(movement.getId());
            mtl.setUserId(userId);
            mtl.setFriendId(friend.getFriendId());
            mtl.setCreated(System.currentTimeMillis());
            mongoTemplate.save(mtl);
        });
    }

    /**
     * 采用mongoDB的方式去分页并查找数据
     * @param userId
     * @param page
     * @param pagesize
     * @return
     */
    @Override
    public PageResult findByUserId(Long userId, Integer page, Integer pagesize) {
        //1 movement表中查
        Criteria criteria = Criteria.where("userId").is(userId);
        Query query = new Query(criteria)
                .skip((page - 1) * pagesize)
                .limit(pagesize)
                .with(Sort.by(Sort.Order.desc("created")));
        //2 执行查询
        List<Movement> movementList = mongoTemplate.find(query, Movement.class);
        //3 准备返回结果
        PageResult pr = new PageResult();
        long count = mongoTemplate.count(new Query(criteria),Movement.class);
        pr.setCounts((int) count);
        pr.setPage(page);
        pr.setPagesize(pagesize);

        int pages = (int) (count%pagesize==0? count/pagesize : (count/pagesize+1));
        pr.setPages(pages);
        pr.setItems(movementList);

        return pr;
    }

    @Override
    public PageResult findByFriendId(Long friendId, Integer page, Integer pagesize) {
        //1 去动态时间线 表中，根据friendId查找出movementId的集合
        Query query = new Query(Criteria.where("friendId").is(friendId))
                .skip((page - 1) * pagesize)
                .limit(pagesize)
                .with(Sort.by(Sort.Order.desc("created")));
        List<MovementTimeLine> movementTimeLineList = mongoTemplate.find(query, MovementTimeLine.class);
        List<ObjectId> movementIdList = movementTimeLineList.stream().map(mtl -> mtl.getMovementId()).collect(Collectors.toList());
        //2 通过movementId的集合查找出movement
        Query query1 = new Query(Criteria.where("id").in(movementIdList));
        List<Movement> movementList = mongoTemplate.find(query1, Movement.class);
        //3 封装结果
        PageResult pr = new PageResult();
        pr.setItems(movementList);
        pr.setPage(page);
        pr.setPagesize(pagesize);
        long count = mongoTemplate.count(new Query(Criteria.where("friendId").is(friendId)),MovementTimeLine.class);
        pr.setCounts((int) count);
        int pages = (int) (count%pagesize==0? count/pagesize : (count/pagesize+1));
        pr.setPages(pages);
        return pr;
    }

    @Override
    public List<Movement> findByPIds(ArrayList<Long> list) {
        Criteria criteria = Criteria.where("pid").in(list);
        Query query = new Query(criteria);

        return mongoTemplate.find(query,Movement.class);
    }

    @Override
    public List<Movement> randomTuijian(Integer pagesize) {
        //1 查出所有
        List<Movement> movementList = mongoTemplate.findAll(Movement.class);
        //2 取出id集合
        List<Long> moveIdList = movementList.stream().map(move -> move.getPid()).collect(Collectors.toList());
        //3 随机,保存pid集合
        ArrayList<Long> randomIdList = new ArrayList<>();
        Random random = new Random();
        for (int i=0;i<pagesize;i++){
            int index = random.nextInt(moveIdList.size());
            randomIdList.add(moveIdList.get(index));
        }
        //4 查询
        Query query = new Query(Criteria.where("pid").in(randomIdList));
        return mongoTemplate.find(query,Movement.class);
    }

    @Override
    public boolean hasComment(String movementId, Long userId, Integer like) {
        Criteria criteria = Criteria.where("publishId").is(movementId)
                .and("commentType").is(like)
                .and("userId").is(userId);
        Query query = new Query(criteria);
        return mongoTemplate.find(query, Comment.class).size()==1;
    }

    @Override
    public Movement findByMovementId(String movementId) {
        Query query = new Query(Criteria.where("id").is(movementId));
        return mongoTemplate.findOne(query,Movement.class);
    }


}
